Correct Bradley–Terry inference and make Rank recovery transactional - #73
Correct Bradley–Terry inference and make Rank recovery transactional#73AliFozooni wants to merge 1 commit into
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read and agree to the GABRIEL CLA. Post the signature and recheck comments for me. |
|
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
|
The required CLA signature is now posted above, and the CLA bot’s conversation message reports that all contributors have signed. The required check nevertheless remains red because the workflow fails before it can persist the signature: The workflow’s |
Motivation
Rankpreviously updated the Bradley–Terry sufficient statistics withn_ij += pseudoandw_i += pseudo. Those two operations do not describe one coherent win matrix: they add denominator mass to every cell (including the diagonal and unobserved pairs), but only one numerator pseudo-win per item. Consequently, adding unrelated items could change an existing pair's contrast, disconnected groups were implicitly linked, and the reported inverse-information standard errors treated synthetic ridge information as observed data. A parsed draw also contributed two full comparisons.Recovery had a second class of correctness risks. A resumed run could mix judgments after the input payload or effective judging specification changed, accept an incomplete or semantically malformed round, or cross a Batch submission/checkpoint gap that could duplicate paid work or lose completed rows.
This PR makes the estimator, uncertainty calculation, outcome semantics, and recovery protocol agree with one another.
Statistical model
For each observed undirected edge, the fitted directed win matrix is now
where
λ = learning_rate. No mass is added to unobserved edges or the diagonal. For an isolated two-item edge this gives the exact contrastThis makes the perturbation symmetric, edge-local, and invariant to unrelated items.
Other inference changes:
insufficient_signal_policy="tie"makes an explicit equality assumption;"abstain"conditions the fit on retained judgments.learning_rate=0now enforces Ford's directed strong-connectivity condition for every nontrivial observed component.NaNscores/SEs, and z-scores are standardized only within identified components.Uncertainty and diagnostics
For each observed component, standard errors use the fixed-graph model-based sandwich
under the component sum-to-zero constraint, where
Lis the graph Laplacian operator andB⁺is the constrained pseudoinverse. Observed comparisons form the meat; fixed pseudo-comparisons add curvature only to the bread.The documentation is explicit that this does not estimate shrinkage bias, shared-judge dependence, likelihood misspecification, adaptive-selection uncertainty, or uncertainty in the reported z-score. Non-recursive runs also write a diagnostics sidecar containing decoded outcome counts, effective comparison weight, graph components, isolates, and finite-SE counts.
Measurement and recovery integrity
response_fn/get_all_responses_fnjudges require an explicitjudge_version, so hidden logic changes cannot silently mix measurement regimes.reset_files=Truerefuses to erase state that may refer to externally active Batch work.The public API now applies the same raw-score projection to fresh and cached outputs, preserves unrelated user columns that happen to end in
_raw/_se, rejects generated-column namespace collisions, and documents recursive output/identifiability behavior.Compatibility
This intentionally changes
Rankestimates that depended on the previous incoherent pseudo-count construction. Rank metadata is versioned, so incompatible historical checkpoints fail closed and requirereset_files=Trueor a newsave_dir. Custom judges additionally need a stablejudge_version.Validation
Committed regression coverage includes closed-form two-item estimates, irrelevant-item invariance, permutation/reversal equivariance, comparison to constrained SciPy likelihood optimization, fractional draws, Ford-condition failures, disconnected components and isolates, fixed-graph sandwich formulas, extreme separation, recursive identifiability, semantic response rejection, crash/retry boundaries, Batch intent recovery, reset safety, fingerprints, and cached API projection.
pytest -q tests/test_rank_statistics.py tests/test_basic.py tests/test_reset_files.py tests/test_checkpoint_timeout_resume.py: 214 passedpytest -q tests/test_imports.py: 7 passedpython -m build: wheel and source distribution built successfullypy_compile, Ruff on the modified Rank/statistics paths, andgit diff --check: passed1e-12through1e-300, with zero SCC-certification failures;λ≈1.65e-227regression completes in about 0.24 s and certifies;The full local suite reports 343 passed, 6 skipped, 12 failed. The same 12 failures occur on base commit
9caced9: they are unrelatedtests/test_plot_utils.pyfailures because Matplotlib 3.11 removedmatplotlib.cm.get_cmap.References